/**
 * File Tools
 * 
 * Tools for file system operations
 */

import { z } from 'zod';
import { readFile, writeFile, readdir, stat, mkdir } from 'fs/promises';
import { join, dirname } from 'path';
import type { ToolDefinition } from '@/types';
import { createTextResult, createErrorResult } from '../tool-factory';
import { logger } from '@/utils/logger';

/**
 * Read file tool
 */
export const readFileTool: ToolDefinition = {
  name: 'read_file',
  description: 'Read the contents of a file from the file system.',
  inputSchema: z.object({
    path: z.string().describe('Path to the file to read'),
    encoding: z.enum(['utf-8', 'base64']).optional().default('utf-8').describe('File encoding'),
  }),
  handler: async (args) => {
    try {
      const { path, encoding } = args;
      
      logger.info(`Reading file: ${path}`);
      
      const content = await readFile(path, encoding as BufferEncoding);
      
      return createTextResult(`File content:\n\n${content}`);
    } catch (error) {
      logger.error(`Failed to read file: ${args.path}`, error);
      return createErrorResult(error as Error);
    }
  },
};

/**
 * Write file tool
 */
export const writeFileTool: ToolDefinition = {
  name: 'write_file',
  description: 'Write content to a file. Creates the file if it doesn\'t exist, or overwrites it if it does.',
  inputSchema: z.object({
    path: z.string().describe('Path to the file to write'),
    content: z.string().describe('Content to write to the file'),
    encoding: z.enum(['utf-8', 'base64']).optional().default('utf-8').describe('File encoding'),
  }),
  handler: async (args) => {
    try {
      const { path, content, encoding } = args;
      
      logger.info(`Writing file: ${path}`);
      
      // Ensure directory exists
      const dir = dirname(path);
      await mkdir(dir, { recursive: true });
      
      await writeFile(path, content, encoding as BufferEncoding);
      
      return createTextResult(`Successfully wrote ${content.length} characters to ${path}`);
    } catch (error) {
      logger.error(`Failed to write file: ${args.path}`, error);
      return createErrorResult(error as Error);
    }
  },
};

/**
 * List directory tool
 */
export const listDirectoryTool: ToolDefinition = {
  name: 'list_directory',
  description: 'List the contents of a directory.',
  inputSchema: z.object({
    path: z.string().describe('Path to the directory to list'),
    recursive: z.boolean().optional().default(false).describe('Whether to list subdirectories recursively'),
  }),
  handler: async (args) => {
    try {
      const { path, recursive } = args;
      
      logger.info(`Listing directory: ${path}`);
      
      const entries = await readdir(path, { withFileTypes: true });
      
      let result = `Contents of ${path}:\n\n`;
      
      for (const entry of entries) {
        const type = entry.isDirectory() ? 'DIR' : 'FILE';
        result += `[${type}] ${entry.name}\n`;
        
        if (recursive && entry.isDirectory()) {
          const subPath = join(path, entry.name);
          const subResult = await listDirectoryTool.handler({ path: subPath, recursive: true });
          result += subResult.content[0].text + '\n';
        }
      }
      
      return createTextResult(result);
    } catch (error) {
      logger.error(`Failed to list directory: ${args.path}`, error);
      return createErrorResult(error as Error);
    }
  },
};

/**
 * Get file info tool
 */
export const getFileInfoTool: ToolDefinition = {
  name: 'get_file_info',
  description: 'Get information about a file or directory (size, modification time, etc.).',
  inputSchema: z.object({
    path: z.string().describe('Path to the file or directory'),
  }),
  handler: async (args) => {
    try {
      const { path } = args;
      
      logger.info(`Getting file info: ${path}`);
      
      const stats = await stat(path);
      
      const info = {
        path,
        type: stats.isDirectory() ? 'directory' : 'file',
        size: stats.size,
        created: stats.birthtime.toISOString(),
        modified: stats.mtime.toISOString(),
        accessed: stats.atime.toISOString(),
      };
      
      return createTextResult(JSON.stringify(info, null, 2));
    } catch (error) {
      logger.error(`Failed to get file info: ${args.path}`, error);
      return createErrorResult(error as Error);
    }
  },
};

/**
 * Search files tool
 */
export const searchFilesTool: ToolDefinition = {
  name: 'search_files',
  description: 'Search for files in a directory by name pattern.',
  inputSchema: z.object({
    directory: z.string().describe('Directory to search in'),
    pattern: z.string().describe('File name pattern to search for (supports wildcards)'),
    recursive: z.boolean().optional().default(true).describe('Whether to search subdirectories'),
  }),
  handler: async (args) => {
    try {
      const { directory, pattern, recursive } = args;
      
      logger.info(`Searching files in ${directory} with pattern: ${pattern}`);
      
      const results: string[] = [];
      
      async function search(dir: string) {
        const entries = await readdir(dir, { withFileTypes: true });
        
        for (const entry of entries) {
          const fullPath = join(dir, entry.name);
          
          if (entry.isDirectory() && recursive) {
            await search(fullPath);
          } else if (entry.isFile()) {
            // Simple pattern matching (convert * to .*)
            const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
            if (regex.test(entry.name)) {
              results.push(fullPath);
            }
          }
        }
      }
      
      await search(directory);
      
      if (results.length === 0) {
        return createTextResult(`No files found matching pattern: ${pattern}`);
      }
      
      return createTextResult(`Found ${results.length} files:\n\n${results.join('\n')}`);
    } catch (error) {
      logger.error(`Failed to search files in ${args.directory}`, error);
      return createErrorResult(error as Error);
    }
  },
};

